/**********************************************************
 *
 *  Copyright (c) 2003  SeikoEpson Inc
 *  All Rights Reserved
 *
 *  File name : f_modef.c
 *  Function  :
 *        f_modef function returns the integer part and fraction part 
 *        whose original value is given.
 *        This file is copied from math.lib of 
 *                  CC33 tool(CC33v40.exe + CCPA45.exe, 
 *                  math of ansilib33v25 )
 *
 *  original file's Revision  :
 *      1993/08/31    first release                 K.Shinozuka
 *      1993/12/17    change include file           K.Shinozuka
 *      1997/03/17     modified                     T.Katahira
 *       change function declaration
 *       to the ANSI style
 *  Revision  :
 *      2003/ 3/11    IrumaSoft M.Takeishi   1.st design
 *
 **********************************************************/


#ifdef UNIX
#include "f_math.h"
#include "f_smcvals.h"

#else
#include <f_math.h>
#include <f_smcvals.h>
#endif

float
f_modf( float x, float * nptr )

	/********************************************************************/
	/*                                                                  */
	/*  The f_modf function devides a floating point number into a      */
	/*  fraction and an integer parts, each of which has the same sign  */
	/*  as the argument.                                                */
	/*  The integer part is stored as a float in the object pointed     */
	/*  to by nptr.                                                     */
	/*                                                                  */
	/*  RETURN    normal: the signed fractional part of x               */
	/*            error : NaN (input error)                             */
	/*                                                                  */
	/********************************************************************/

/* ALGORITHM
 * 1.get the fraction part as xfrac and exponent part as xexp from the argument
 * 2.clear fractional bits, if x can be separate into the fraction and the integer
 * 3.get the fractional number by subtracting the integer from x 
 */

/*  the architecture of float floating point
 *
 *   0 30         23 22                0  32 bit
 *   -----------------------------------
 *  | |   exponent  |  fraction         |
 *   -----------------------------------
 *
 *  |               |                   |
 *  |    8 bits     |    23 bits        |
 *
 *         bit    31         sign bit        (  1 bit  )
 *             30 - 23      exponent part    (  8 bits )
 *             22 -  0      fraction part    ( 23 bits )
 *
 */
 
	/* float       x;           input value                              */
	/* float       *nptr;       the pointer, the integer to be stored    */
	{
	 FLT_LNG       ckarg;       /* exchange the type to check the argument  */
	 FLT_LNG       ipart;       /* integer stored in nptr                   */
	 FLT_LNG       xfrac;       /* fraction part of x                       */
	 register long xexp;        /* exponential part of x                    */
	 register int  sign;        /* sign of x, 1 ( x>0 ) or -1 ( x<0 )       */

/* check the argument */	
	 *nptr = f_NAN._F;                          /* domein error */
	 ckarg._F = x;
	 F_CHECK_ARG( &ckarg );                     /* check NaN */
	                                          /* error: error code 33 domain error */
 
	 if ( F_GET_EXP_RAW( ckarg.st._LL)  == F_GET_EXP_RAW(f_N_INF.st._LL) ) {   /* Inf or -Inf */
	    errno = ERANGE;                       /* 34: range error */
	    *nptr = x;
	    return( 0.0f );
	 }

	 if ( x < 0.0f ) {                         /* check the sign of x */
	    x = - x;
	    sign = -1;
	 } else if ( x == 0.0f ) {
	    *nptr = 0.0f;
	    return ( 0.0f );
	 } else {
	    sign = 1;
	 }

/* separate x into fraction & exponent part */
	 xfrac._F = x;                
	 xexp = (( xfrac.st._LL & F_MASK_EXP ) >> F_L_FRAC );    /* get exponent part  */
	                                          /* MASK_EXP = 0x7f800000 */
	 xexp = ( xexp - ((unsigned long)F_NUM1_L >> F_L_FRAC) );    /* get off offset */
	                                          /* NUM1_L = 0x3ff00000 */
	 xfrac.st._LL = ( xfrac.st._LL &  F_MASK_FRAC );    /* get fraction part  */
	                                          /* MASK_FRAC = 0x007fffff */
	 if ( xexp >= F_N_FRAC ) {                  /* no fractional bits  */
	    ipart._F = x;                         /* set integer */
	    x = 0.0f;                             /* set fraction */
	 } else if ( xexp < 0 ) {                 /* x < 1 : all fractional bits */
	    ipart._F = 0.0f;                      /* set integer */
	 } else {
	    ipart._F = x;
	    
	    ipart.st._LL = ( ipart.st._LL & ~( (unsigned long)F_MASK_FRAC >> xexp ));
	    x = x - ipart._F;                     /* get fraction */
	 }
	 if ( ipart._F == 0.0f ) {                /* -0.0 is not allowed */
	    *nptr = 0.0f;
	 } else {
	    *nptr = (float)sign * ipart._F;
	 }
	 if ( x == 0.0f ) {                      /* -0.0 is not allowed */
	    return( x );
	 }
	 return( (float)sign * x );
	}
